package com.rongxunwu.netty.NioChat;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;

/**
 * TODO
 *
 * @author WuRongXun
 * @version 1.0
 * @date 2021/11/16 19:57
 */
public class NioChatServer {
    private Selector selector;
    private ServerSocketChannel listserverSocketChannel;
    private static final int port=6666;
    //构造器 初始化
    public  NioChatServer(){
        try {
            //得到选择器
            selector=Selector.open();
            //ServerSocketChannel
            listserverSocketChannel = ServerSocketChannel.open();
            //绑定端口
            listserverSocketChannel.socket().bind(new InetSocketAddress(port));
            //设置非阻塞模式
            listserverSocketChannel.configureBlocking(false);
            //将listserverSocketChannel 注册到selector
            listserverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);


        }catch (Exception e){
            System.out.printf(e.getMessage());
        }
    }
    //监听
    public void listTen(){
        try {
            //循环监听
            while (true){
                int select = selector.select(3000);
                if (select>0){
                    //遍历selectionKey
                    Iterator<SelectionKey> iterator=selector.selectedKeys().iterator();
                    while (iterator.hasNext()){
                        //取出selectionKey
                        SelectionKey selectionKey=iterator.next();
                        //监听到accept
                        if (selectionKey.isAcceptable()){
                            SocketChannel sc=listserverSocketChannel.accept();
                            //设置非阻塞
                            sc.configureBlocking(false);
                            //将sc 注册到seletor
                            sc.register(selector,SelectionKey.OP_READ);
                            //提示
                            System.out.printf(sc.getRemoteAddress()+"  上线了》》》》》》》》》》》》》》");
                        }
                        //通道发送read 事件 即通道是可读状态
                        if (selectionKey.isReadable()){
                            //处理读
                            readDate(selectionKey);
                        }
                        //将当前 key 删除 ，防止重复处理
                        iterator.remove();
                    }
                }else {
                    System.out.printf("\n等待》》》》》");
                }
            }
        }catch (Exception exception){
            System.out.printf("\n监听listTen "+exception.getMessage());
        }
    }

    //读取客户端消息
    private void readDate(SelectionKey key){
        //取到相关的channel
        SocketChannel channel=null;
        try {
            //得到channel
            channel=(SocketChannel)key.channel();
            //创建buffer
            ByteBuffer byteBuffer=ByteBuffer.allocate(1024);
            int count = channel.read(byteBuffer);
            //根据count 值进行处理
            if (count>0){
                //把缓冲区的数据转成字符串
                String msg=new String(byteBuffer.array());
                //输出消息
                System.out.printf("\nfrom 客户端： "+msg);

                //向其他的客户端转发消息
                SendInfoOtherClient(msg,channel);
            }

        }catch (Exception e){
            System.out.printf("\nreadDate: "+e.getMessage());
            try {
                System.out.printf(channel.getRemoteAddress()+" 离线了。。。。。。。。\n");
                //取消注册
                key.cancel();
                //关闭通道
                channel.close();
            } catch (IOException ioException) {
                System.out.printf("\nreadDate: "+ioException.getMessage());
            }
        }
    }
    //转发消息 到其他客户端

    private void SendInfoOtherClient(String msg,SocketChannel self){
        try {
            System.out.printf("\n服务器转发消息中》》》》》》");
            //遍历所有 注册到selector 上的SocketChannel,并排除自己（self）
            for (SelectionKey key:selector.keys()){
                Channel channel=key.channel();
                //排除自己
                if (channel instanceof SocketChannel && channel!=self){
                    //转型
                    SocketChannel dest= (SocketChannel) channel;
                    //将msg 存储到buffer
                    ByteBuffer byteBuffer=ByteBuffer.wrap(msg.getBytes());
                    //将buffer 的数据写到通道
                    dest.write(byteBuffer);
                }
            }
        }catch(IOException e){
            System.out.printf("\n转发消息 到其他客户端失败: "+e.getMessage());
        }

    }

    public static void main(String[] args) {
        NioChatServer nioChatServer = new NioChatServer();
        nioChatServer.listTen();
    }
}
